package Demo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: DELL
 * Date: 2023-01-08
 * Time: 9:31
 */

/**
 * 创建一个类Result， 包含一个sum表示最终结果， lock表示线程同步使用的对象
 * main 方法中先创建Result的实例， 然后创建一个线程t 在线程内部计算1+ 2 + 3+ 4+ 5...
 * 主线程同时使用wait等待线程t计算结束（如果执行到wait之前，线程已经计算完了就不必在等待了）
 * 当线程t计算完毕后， 通过notify 唤醒主线程，主线程在打印结果
 */

class Result {
    // Result 在此处为一个辅助类
    public int sum = 0;
    public Object lock = new Object();

}

class Theread_Demo13 {
    /*public static void main(String[] args) {
        Result result = new Result();
        Thread thread = new Thread() {
            @Override
            public void run() {
                int ret = 0;
                for (int i = 0; i <= 1000; i++) {
                    ret+=i;
                    // 计算和
                }
                synchronized (result.lock) {
                    result.sum = ret; // 将结果赋值给sum 由sum负责输出
                    result.lock.notify(); // 计算结束后唤醒外部wait
                }
            }
        };
        thread.start(); //
        synchronized (result.lock) {
            while(result.sum == 0) {
                // sum未赋值成功或者线程内部未计算结束阻塞等待
                try {
                    result.lock.wait();
                    System.out.println(result.sum);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }*/


    /**
     * Callable 和 Runnable 相对， 都是描述一个“任务” 。
     * 区别为： Callable 描述的是带有返回值的任务 Runnable描述的是不带有返回值的任务
     * Callable通常需要搭配FutureTask来使用： FutureTask用来保存Callable的返回值
     * 因为Callable往往是在另一个线程中执行的，什么时候执行完并不确定
     * FutrueTask就可以负责等待这个结果出来的工作
     * Callable 是一个interface 相当于把线程封装了一个“返回值”。 方便程序员借助多线程的方式计算结果
     *
     * FutrueTask的理解： 看作是点餐是等待的那个小票，等待做好后，可以凭借小票取到自己的那份餐
     */

    public static void main(String[] args) {
        // Callable<?> 为一个泛型 用什么类型取决于返回值类型
        Callable<Integer> callable = new Callable<Integer>() {
            // 默认为一个匿名内部类
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i <= 1000; i++) {
                    sum+=i;
                }
                return sum;
            }
        };

        // FutureTasl<?> 类型取决于Callable的类型  实例中存放Callable的实例
        FutureTask<Integer> futureTask = new FutureTask<>(callable);// 等待Callable任务结束带回结果
        Thread thread = new Thread(futureTask); // 存放Runnable任务
        thread.start();
        try {
            Integer ret = futureTask.get();
            // futureTask有两个异常需要捕获处理 可以方法throw Exception（包括所有异常）
            System.out.println(ret);
            //使用Callable和FuturTask后简化了很多代码，也不必手动写线程的同步代码
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}